package org.xbdframework.boot.autoconfigure.trace;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.xbdframework.trace.interceptor.MethodMapTraceAttributeSource;
import org.xbdframework.trace.interceptor.TraceAttributeSourceAdvisor;
import org.xbdframework.trace.interceptor.TraceInterceptor;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;

/**
 * trace class、method信息存储在{@link Map}中的运行轨迹追踪记录自动化配置.
 * <p>{@code TraceAttributeSource}为{@link MethodMapTraceAttributeSource}.
 * <p>如启用此自动化配置，需实现{@link TraceMethodMapCustomizer}接口并注册为Bean.
 *
 * @author luas
 * @since 1.5.0
 * @see MethodMapTraceAttributeSource
 * @see TraceMethodMapCustomizer
 * @see TraceAttributeSourceAdvisor
 * @see org.xbdframework.trace.interceptor.TraceAttributeSourcePointcut
 */
@Configuration
@AutoConfigureAfter(TraceAutoConfiguration.class)
@ConditionalOnBean(TraceMethodMapCustomizer.class)
public class MethodMapTraceAutoConfiguration {

    private Set<TraceMethodMapCustomizer> traceMethodMapCustomizers;

    public MethodMapTraceAutoConfiguration(ObjectProvider<Set<TraceMethodMapCustomizer>> traceMethodMapCustomizersObjectProvider) {
        this.traceMethodMapCustomizers = traceMethodMapCustomizersObjectProvider.getIfAvailable();
    }

    @Bean
    public TraceInterceptor methodMapTraceInterceptor() {
        TraceInterceptor interceptor = new TraceInterceptor();

        customize(interceptor);

        return interceptor;
    }

    @Bean
    public TraceAttributeSourceAdvisor methodMapTraceAttributeSourceAdvisor() {
        TraceAttributeSourceAdvisor advisor = new TraceAttributeSourceAdvisor();
        advisor.setTraceInterceptor(methodMapTraceInterceptor());
        return advisor;
    }

    private void customize(TraceInterceptor traceInterceptor) {
        if (!CollectionUtils.isEmpty(this.traceMethodMapCustomizers)) {
            List<MethodMapTraceAttributeSource> attributeSources = new ArrayList<>();

            for (TraceMethodMapCustomizer customizer : this.traceMethodMapCustomizers) {
                attributeSources.add(customizer.customize());
            }

            traceInterceptor.setTraceAttributeSources(attributeSources.toArray(new MethodMapTraceAttributeSource[] {}));
        }
    }
}
